package com.rj.core.algorithm;

import com.rj.util.ByteUtils;
import com.rj.util.PrintUtils;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HexFormat;

public class CryptoExample {
    public static void main(String[] args) throws Exception {

        //对称加密
        SymmetricAlgorithm aesCbc = SymmetricAlgorithm.SM4_CBC;
        byte[] iv = aesCbc.generateIv();
        byte[] key = aesCbc.generateKey();
        System.out.println(Hex.decode("4290e5669aeb80d85cac1fdad3361513").length);
        byte[] dataBytes = "需要加密的敏感数据".getBytes();
        byte[] encrypt = CryptoUtils.encrypt(aesCbc, dataBytes, key, iv);
        System.out.println(ByteUtils.encodeBase64String(encrypt));
        byte[] decrypt = CryptoUtils.decrypt(aesCbc, encrypt, key, iv);
        System.out.println(new String(decrypt));
        //哈希运算
        HashAlgorithm hashAlgorithm = HashAlgorithm.SHA256;
        byte[] hash = CryptoUtils.hash(hashAlgorithm, dataBytes);
        System.out.println(ByteUtils.toHexString(hash, true));
        //哈希运算
        HmacAlgorithm hmacAlgorithm = HmacAlgorithm.HMAC_SHA256;
        byte[] hmacHash = CryptoUtils.hash(hmacAlgorithm, dataBytes, key);
        System.out.println(ByteUtils.toHexString(hmacHash, true));

        //非对称加密
        RsaAgorithm rsaAgorithm = RsaAgorithm.RSA_ECB_PKCS1PADDING;
        KeyPair keyPair = rsaAgorithm.generateRsaKeyPair();
        PublicKey aPublic = keyPair.getPublic();
        PrivateKey aPrivate = keyPair.getPrivate();

        byte[] encrypt2 = CryptoUtils.encrypt(rsaAgorithm, dataBytes, aPublic.getEncoded());
        System.out.println(ByteUtils.encodeBase64String(encrypt2));
        byte[] decrypt2 = CryptoUtils.decrypt(rsaAgorithm, encrypt2, aPrivate.getEncoded());
        System.out.println(new String(decrypt2));


        try {
            System.out.println("=== SM2算法完整测试 ===\n");
            SM2Algorithm sm2 = SM2Algorithm.SM2;
            // 1. 生成密钥对
            System.out.println("1. 生成SM2密钥对...");
            keyPair = sm2.generateKeyPair();
            byte[] hexPublicKey = sm2.getPublicKey(keyPair.getPublic(), false);
            byte[] hexPrivateKey = sm2.getPrivateKey(keyPair.getPrivate());
            PrintUtils.print("=== SM2算法完整测试 ===%s", hexPublicKey);

            System.out.println("hexPublicKey公钥: " + hexPublicKey);
            System.out.println("hexPrivateKey私钥: " + hexPrivateKey);
            System.out.println("公钥: " + Hex.toHexString(keyPair.getPublic().getEncoded()));
            System.out.println("私钥: " + Hex.toHexString(keyPair.getPrivate().getEncoded()));
            BCECPublicKey publicKey = sm2.getPublicKey(hexPublicKey);
            BCECPrivateKey privateKey = sm2.getPrivateKey(hexPrivateKey);
            System.out.println("公钥: " + sm2.getPublicKey(publicKey, false));
            System.out.println("私钥: " + sm2.getPrivateKey(privateKey));

            // 2. 签名验签测试
            System.out.println("\n2. 签名验签测试...");
            byte[] userIdBytes = "123123".getBytes();
            byte[] signature = CryptoUtils.sign(sm2, dataBytes, sm2.getPrivateKey(privateKey), userIdBytes);
            System.out.println("签名结果: " + Hex.toHexString(signature));

            boolean verifyResult = CryptoUtils.verify(sm2, dataBytes, signature, sm2.getPublicKey(publicKey, false),
                    userIdBytes);
            System.out.println("验签结果: " + verifyResult);

            // 3. 加密解密测试
            System.out.println("\n3. 加密解密测试...");
            String secretMessage = "这是需要加密的敏感数据";

            byte[] encrypted = CryptoUtils.encrypt(sm2, dataBytes, hexPublicKey, SM2Engine.Mode.C1C3C2);
            System.out.println("加密后: " + Hex.toHexString(encrypted));

            byte[] decrypted = CryptoUtils.decrypt(sm2, encrypted, hexPrivateKey, SM2Engine.Mode.C1C3C2);
            String decryptedMessage = new String(decrypted);
            System.out.println("解密后: " + decryptedMessage);
            System.out.println("加解密是否一致: " + secretMessage.equals(decryptedMessage));

            System.out.println("\n=== 测试完成 ===");

            //16进制
            //私钥添加00
            //公钥|数据添加04
            byte[] res = CryptoUtils.decrypt(sm2,
                    Hex.decode("040325a69ea184a682500ebb19d64145187364f0d382910602fcf02dec719eeaf64243e5f692ec1739caad5242962b906934ddd6a6858fdb6473f07464dcd00b0dfc1942b25f247be69450afd6d20572aa8107a01aec0cf785edffc223a06e994a5c1b04397dd1b6af63b9163e1825291f89cbbab107813edf4f7840d68e2fadf5"),
                    Hex.decode("002066bd3a52c24ee86588ba3b76ce3057e3c7517870cc3b7e31100d894f612549"),
                    SM2Engine.Mode.C1C3C2);
            System.out.println("caeed2261eaa224aac01a6d58b54ccf0".getBytes().length);
            System.out.println(new String(res).equals("caeed2261eaa224aac01a6d58b54ccf0"));

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}